package com.hmdp.service.impl;

import cn.hutool.core.text.Simhash;
import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.SimpleLock;
import com.hmdp.utils.UserHolder;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {
    @Resource
    private ISeckillVoucherService seckillVoucherService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Resource
    private RedisIdWorker worker;
    @Override
    public Result seckillVoucher(Long voucherId) {
        //判断秒杀券时间是否开始
        SeckillVoucher voucher = seckillVoucherService.getById(voucherId);
        //判断是否卖完
        //已经未开始
        if (voucher.getBeginTime().isAfter(LocalDateTime.now())) {
            return Result.fail("秒杀还未开始");
        }
        //已经结束
        if (voucher.getEndTime().isBefore(LocalDateTime.now())) {
            return Result.fail("秒杀已经结束");
        }
        //否则在一
        if (voucher.getStock() < 1) {
            return Result.fail("库存不足");
        }
        return check(voucherId);
    }

//    @Transactional
//    public Result check(Long voucherId) {
//        //实现一人一单
//        Long userId = UserHolder.getUser().getUserId();
//        //intern(),值一样，返回的地址也是一样，这里避免了userId防止
//        //底层userId.toString()还是返回的是一个new String()
//        SimpleLock simpleLock = new SimpleLock("order:" + userId, redisTemplate);
//        //尝试获取锁
//        boolean b = simpleLock.tryLock(10L);
//        if(!b){
//            //获取锁失败
//            return Result.fail("不允许重复订单");
//        }
//        try {
//            Long count = query().eq("user_id", userId)
//                    .eq("voucher_id", voucherId).count();
//            if (count > 0) {
//                return Result.fail("每个用户只能订购一单");
//            }
//            //减一
//            boolean success = seckillVoucherService.update()
//                    .setSql("stock = stock - 1")
//                    .eq("voucher_id", voucherId)
//                    .gt("stock", 0)//这里是通过乐观锁，简单的实现了解决防止超卖的问题
//                    .update();
//            if (!success) {
//                return Result.fail("库存不足");
//            }
//            VoucherOrder voucherOrder = new VoucherOrder();
//            //创建订单
//            //订单id
//            voucherOrder.setId(worker.workId("order"));
//            //用户id
//            voucherOrder.setUserId(UserHolder.getUser().getUserId());
//            //代金券id
//            voucherOrder.setVoucherId(voucherId);
//            //存入数据库
//            save(voucherOrder);
//            return Result.ok("秒杀成功");
//        }finally {
//            simpleLock.unLock();
//        }
//
//
//    }
    //悲观锁实现
//    @Transactional
//        public synchronized Result check(Long voucherId) {
//        //实现一人一单
//        Long userId = UserHolder.getUser().getUserId();
//        //intern(),值一样，返回的地址也是一样，这里避免了userId防止
//        //底层userId.toString()还是返回的是一个new String()
//        synchronized (userId.toString().intern()) {
//            Long count = query().eq("user_id", userId)
//                    .eq("voucher_id", voucherId).count();
//            if (count > 0) {
//                return Result.fail("每个用户好、只能订购一单");
//            }
//            //减一
//            boolean success = seckillVoucherService.update()
//                    .setSql("stock = stock - 1")
//                    .eq("voucher_id", voucherId)
//                    .gt("stock", 0)//这里是通过乐观锁，简单的实现了解决防止超卖的问题
//                    .update();
//            if (!success) {
//                return Result.fail("库存不足");
//            }
//            VoucherOrder voucherOrder = new VoucherOrder();
//            //创建订单
//            //订单id
//            voucherOrder.setId(worker.workId("order"));
//            //用户id
//            voucherOrder.setUserId(UserHolder.getUser().getUserId());
//            //代金券id
//            voucherOrder.setVoucherId(voucherId);
//            //存入数据库
//            save(voucherOrder);
//            return Result.ok("秒杀成功");
//        }
//    }
    @Autowired
    RedissonClient redissonClient;
@Transactional
public Result check(Long voucherId) {
    //实现一人一单
    Long userId = UserHolder.getUser().getUserId();
    //intern(),值一样，返回的地址也是一样，这里避免了userId防止
    //底层userId.toString()还是返回的是一个new String()
    RLock redisLock = redissonClient.getLock("lock:order:" + userId);
    //尝试获取锁
    boolean b = redisLock.tryLock();//默认-1
    if(!b){
        //获取锁失败
        return Result.fail("不允许重复订单");
    }
    try {
        Long count = query().eq("user_id", userId)
                .eq("voucher_id", voucherId).count();
        if (count > 0) {
            return Result.fail("每个用户只能订购一单");
        }
        //减一
        boolean success = seckillVoucherService.update()
                .setSql("stock = stock - 1")
                .eq("voucher_id", voucherId)
                .gt("stock", 0)//这里是通过乐观锁，简单的实现了解决防止超卖的问题
                .update();
        if (!success) {
            return Result.fail("库存不足");
        }
        VoucherOrder voucherOrder = new VoucherOrder();
        //创建订单
        //订单id
        voucherOrder.setId(worker.workId("order"));
        //用户id
        voucherOrder.setUserId(UserHolder.getUser().getUserId());
        //代金券id
        voucherOrder.setVoucherId(voucherId);
        //存入数据库
        save(voucherOrder);
        return Result.ok("秒杀成功");
    }finally {
        redisLock.unlock();
    }


}
}
